import * as events from 'events';
import * as ws from 'ws';

import * as log from '../log/log';
import * as wsEvent from './event-websocket';
import * as protobuf from '../protobuf/protobuf-msg';

/**
 * websocket的客户端对象，可以建立监听服务
 * @author yangxiao
 */
export class ClientWebSocket extends events.EventEmitter{

    private websocket:ws;
    private host:string;
    private port:number=80;
    private isOpen=false;  
    private isExcresumeConnection=false;
    private excresumeConnectionTime=2000;
    
    /**
     * 
     * @memberOf ClientWebSocket
     */
    public isAutoConnection=true;
    /**
     * 
     * @memberOf ClientWebSocket
     */
    public headers={"serverid":""};

    constructor(host?:string,port=80){
        super();
        if(host){
            this.Connection(host,port);
        }
    }

    
    /**
     * 
     * 
     * @param {string} host
     * @param {number} [port]
     * 
     * @memberOf ClientWebSocket
     */
    public Connection(host:string,port?:number){
        this.host = host;
        this.port = port;
        var address = this.host;
        if (this.port) {
            address ="ws://" + this.host + ":" + this.port;
        }
        this.websocket = new ws(address,{"headers":this.headers});
        this.websocket.on("open",()=>this.open());
        this.websocket.on('close',()=>this.close());
        this.websocket.on('error',(err)=>this.error(err));
        this.websocket.on('message', (results,flags)=>this.handleMessage(results,flags));
    }

    
    /**
     * 
     * 
     * @returns {ws}
     * 
     * @memberOf ClientWebSocket
     */
    public getClient():ws{
        return this.websocket;
    }

    /**
     *  发送具体对象到
     * 
     *        let classs = protobuf.getMsgProto();
     *        let test = new classs.login_login_c2s();
     *        test.user_name = "yangxiao";
     *        this.send(protoBufMsg.head.msg_login_login_c2s,test);
     * 
     * @param {number} head protoBufMsg.head
     * @param {any} msgClass let classs = protobuf.getMsgProto();
     * 
     * @memberOf ClientWebSocket
     */
    public send(message,cb?:(err)=>void){

        if(typeof('msgClass')==='function'){
            throw new Error('lib.net.client-websocket msgClass not | new msgClass');
        }
        if(this.websocket==null){
            throw new Error('lib.net.client-websocket sen websocket==null ');
        }
        if(!this.isOpen){
            log.error('lib.net.client-websocket send isOpen = false');
            return;
        }
        this.websocket.send(message, { binary: true, mask: true },cb);
    }


    /**
     * 
     * 
     * @private
     * @param {Buffer} results
     * @param {any} flags
     * 
     * @memberOf ClientWebSocket
     */
    private handleMessage(results:Buffer,flags){
        let classs = protobuf.getMsgProto();
        this.emit(wsEvent.Event.clientMessage,results);
    }


    
    /**
     * 
     * 
     * @private
     * 
     * @memberOf ClientWebSocket
     */
    private open(){
        this.isOpen = true;
        this.emit(wsEvent.Event.open); 
    }

    
    /**
     * 
     * 
     * @private
     * 
     * @memberOf ClientWebSocket
     */
    private close(){
        this.isOpen = false;
        this.emit(wsEvent.Event.clientClose);
        log.error("lib.net.client-websocket close",this.host);
        this.setResumeConnection();
    }

    
    /**
     * 
     * 
     * @private
     * @param {any} err
     * 
     * @memberOf ClientWebSocket
     */
    private error(err){
        this.isOpen = false;
        this.emit(wsEvent.Event.clientError);
        log.error("lib.net.client-websocket error",err);
        this.setResumeConnection();
        
    }

    /**
     * 自动重连
     * 
     * @private
     */
    private resumeConnection(){
        
        if(!this.isAutoConnection){
            return
        }
        if(this.isOpen){
            return;
        }
        if(this.websocket!=null){
            this.websocket.removeAllListeners();
        }
        this.Connection(this.host,this.port);
    }

    private setResumeConnection(){
        if(this.isExcresumeConnection ){
            return;
        }
        this.isExcresumeConnection  = true;
        setTimeout(()=>{
            this.resumeConnection();
            this.isExcresumeConnection  = false;
        },this.excresumeConnectionTime);
    }

    


}